/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package fiarproject;

import java.util.Stack;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

/**
 * @author Luke Richardson
 * @author Pok Ng
 */

public class GameInput {
    // Constants for String values of board pieces used by user
    private static final String BLACK_STRING = "B";
    private static final String WHITE_STRING = "W";
    private static final String EMPTY_STRING = "-";
    private static final String DELIMITER = " ";

    private int width;
    private int[][] tempArray;
    private String[] inputArray ;
    private Stack<Integer> errorStack = new Stack<Integer>();

    /**
     *  Initialises primitive arrays with width parameter in order create board with correct dimensions.
     * @param width Value entered by user defining 'n'
     * @param inputArray String array passed from UserInterface taken from StdIn
     */
    public GameInput(int width, String[] inputArray) {
        this.inputArray = inputArray;
        this.width = width;
        tempArray = new int[width][width];
    }

    /**
     * Method takes array of strings from StdIn which is passed from UserInterface and returns a Board object populated
     * with board pieces.
     * @return Board object containing populated board
     * @throws FiarException If any of the lines input contain syntax errors
     */
    public Board inputGame() throws FiarException {
        for (int i = 0; i < width; i++) {
            try {
                tempArray[i] = parseLine(inputArray[i]);
            }
            catch(FiarException e) {
                errorStack.push(i);
            }
        }
        if (!errorStack.empty()) throw new FiarException(errorStack);
        return new Board(tempArray);
        }

    /**
     * Takes a line of input and creates a StringTokenizer object, with the delimiter as whitespace character. The
     * helper method regexCheck() is then invoked to check if the input conforms to the expected syntax. If an
     * exception is not thrown then each line is iterated over with the help of the matchPiece() method to match
     * the String input to the BLACK, WHITE or EMPTY constant.
     * @param line String from StdIn
     * @return Int array containing board line with int values instead of String
     */
    private int[] parseLine(String line) throws FiarException {
        if(!regexCheck(line)) throw new FiarException("Regex match failure");
        StringTokenizer t = new StringTokenizer(line, DELIMITER);
        int[] boardRow = new int[width];

        for(int i = 0; t.hasMoreElements(); i++) {
                boardRow[i] = matchPiece(t.nextToken());
        }
        return boardRow;
    }

    /**
     * Matches the string input to a piece constant BLACK, WHITE or EMPTY. If none of the strings match, then an
     * exception is thrown. This should never happen as regexCheck() should ensure that each line only contains
     * whitespace and those three input characters.
     * @param piece Board piece from input fiargame
     * @return int Value corresponding to piece String value
     * @throws FiarException
     */
    private int matchPiece(String piece) throws FiarException {
            if(piece.equals(BLACK_STRING)) return FiarGame.BLACK;
            else if(piece.equals(WHITE_STRING)) return FiarGame.WHITE;
            else if(piece.equals(EMPTY_STRING)) return FiarGame.EMPTY;
            else {
                throw new FiarException("Serious regular expression failure with input: " + piece + ".");
            }
    }

    /**
     * Ensures that the String passed matches the regular expression ((b|w|-)\\s{width-1})(b|w|-)
     * @param line Line of fiar game
     * @return true Iff regex matches input
     */
    private boolean regexCheck(String line) {
        Pattern p = Pattern.compile("((" + BLACK_STRING + "|" + WHITE_STRING + "|" + EMPTY_STRING + ")" + "\\s" + ")" +
                "{" + (width-1) + "}" + "+" + "(" + BLACK_STRING + "|" + WHITE_STRING + "|" + EMPTY_STRING + ")");
        return p.matcher(line).matches();
    }
}
